class Vue {
  constructor(obj_instance) {
    this.$data = obj_instance.data;
    Observer(this.$data);
    Compile(obj_instance.el, this);
  }
}

//数据劫持  监听实例里面的数据
function Observer(data_instance) {
  //递归出口
  if (!data_instance || typeof data_instance !== "object") return;
  const dependency = new Dependency();
  Object.keys(data_instance).forEach(v => {
    let value = data_instance[v];
    Observer(value);
    Object.defineProperty(data_instance, v, {
      enumerable: true,
      configurable: true,
      get() {
        console.log(`${v}:${value}属性被访问`);
        //订阅者加入依赖实例的数组
        Dependency.temp && dependency.addSub(Dependency.temp);
        return value;
      },
      set(newValue) {
        console.log(`${v}:${value}属性被修改成${v}:${newValue}`);
        value = newValue;
        Observer(newValue);
        dependency.notify();
      },
    });
  });
}

//解析html模板
function Compile(element, vm) {
  console.log(element, vm);
  //element：元素, vm：vm实例
  vm.$el = document.querySelector(element);
  //创建文档碎片
  let fragment = document.createDocumentFragment();
  let child;
  while ((child = vm.$el.firstChild)) {
    fragment.append(child);
  }
  //解析文档碎片内容，将插值语法里面的数据替换成data里面的数据
  FragmentCompile(fragment);
  function FragmentCompile(node) {
    const pattern = /\{\{\s*(\S+)\s*\}\}/;
    if (node.nodeType === 3) {
      const xxx = node.nodeValue;
      const result_regex = pattern.exec(node.nodeValue);
      if (result_regex) {
        const arr = result_regex[1].split(".");
        const value = arr.reduce((total, current) => total[current], vm.$data);
        node.nodeValue = xxx.replace(pattern, value);
        //文本替换的时候，创建订阅者
        new Watch(vm, result_regex[1], newValue => {
          node.nodeValue = xxx.replace(pattern, newValue);
        });
      }
      return;
    }
    //视图改变更新data
    if (node.nodeType === 1 && node.nodeName === "INPUT") {
      const attr = Array.from(node.attributes);
      attr.forEach(i => {
        if (i.nodeName === "v-model") {
          const value = i.nodeValue.split(".").reduce((total, current) => total[current], vm.$data);
          node.value = value;
          new Watch(vm, i.nodeValue, newValue => {
            node.value = newValue;
          });
          node.addEventListener("input", e => {
            const arr1 = i.nodeValue.split(".");
            const arr2 = arr1.slice(0, arr1.length - 1);
            const final = arr2.reduce((total, current) => total[current], vm.$data);
            final[arr1[arr1.length - 1]] = e.target.value;
          });
        }
      });
    }

    node.childNodes.forEach(child => FragmentCompile(child));
  }
  vm.$el.append(fragment);
}

//收集依赖  收集和通知订阅者
class Dependency {
  constructor() {
    this.subscribers = [];
  }
  addSub(sub) {
    this.subscribers.push(sub);
  }
  notify() {
    this.subscribers.forEach(v => v.update());
  }
}

//订阅者
class Watch {
  constructor(vm, key, callback) {
    this.vm = vm;
    this.key = key;
    this.callback = callback;
    //临时属性-触发getter
    Dependency.temp = this;
    key.split(".").reduce((total, current) => total[current], vm.$data);
    Dependency.temp = null;
  }

  update() {
    const value = this.key.split(".").reduce((total, current) => total[current], this.vm.$data);
    console.log(value, "valuevalue");
    this.callback(value);
  }
}
